Skip to content

fix(ci,api-server): add control-plane + mcp to build pipelines, fix migration parameter mismatch#1426

Merged
mergify[bot] merged 10 commits intomainfrom
fix/ci-control-plane-and-migration
Apr 22, 2026
Merged

fix(ci,api-server): add control-plane + mcp to build pipelines, fix migration parameter mismatch#1426
mergify[bot] merged 10 commits intomainfrom
fix/ci-control-plane-and-migration

Conversation

@markturansky
Copy link
Copy Markdown
Contributor

@markturansky markturansky commented Apr 22, 2026

Summary

  • CI: ambient-control-plane — Added ambient-control-plane to both components-build-deploy.yml and prod-release-deploy.yaml (build matrix, path triggers, kustomize image pinning in deploy jobs). This was completely missing from CI, causing vteam_control_plane to have no latest or release tags.

  • CI: ambient-mcp — Migrated components/ambient-mcp/ source from alpha branch (16 files: Go MCP server with 16 tools, Dockerfile, tests). Added to both CI workflows (build matrix, path triggers, kustomize image pinning). Manifests and control-plane code on main already reference quay.io/ambient_code/vteam_mcp but no source or CI pipeline existed.

  • api-server migration fix — Fixed GORM FirstOrCreate parameter mismatch in plugins/roles/migration.go and plugins/credentials/migration.go. GORM extracted pre-populated ID as an additional WHERE bind parameter, but the SQL only had 1 placeholder from .Where("name = ?", ...). Changed to use .Attrs() which defers field assignment to create-time only.

Test plan

  • go vet ./... passes for ambient-mcp and ambient-api-server
  • go build ./... passes for ambient-api-server
  • Workflow YAML syntax validated (matrices, path triggers, deploy steps)
  • Cluster patched with :alpha tag as immediate fix for control-plane ImagePullBackOff

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added a new ambient-mcp service (build, runtime image, API client, server/tools, mention resolution, token exchange) and added ambient-control-plane/ambient-mcp to release/build pipelines.
  • Improvements

    • Shared HTTP clients and a transport wrapper improve session-token handling for backend runner requests.
    • Simplified role seeding logic.
  • Tests

    • Extensive tests for session-token behavior, token-exchange, client concurrency, mention resolution, and MCP tools.

user and others added 8 commits April 21, 2026 15:59
…hancements, and Kustomize overlays from alpha

PR 6 of alpha-to-main migration (combined with PR 7 — manifests).

Runners:
- gRPC transport for session message streaming
- gRPC client for control-plane token endpoint
- Inbox and session messages APIs with delta buffer
- Credential system: fetch/populate/clear, gh CLI wrapper
- SSE flush-per-chunk, unbounded tap queue
- CP OIDC token for backend credential fetches (RSA keypair auth)
- New deps: cryptography, grpcio, protobuf
- Tests: grpc_client, grpc_transport, grpc_writer, events_endpoint,
  app_initial_prompt, expanded bridge_claude and shared_session_credentials

Manifests:
- mpp-openshift overlay: NetworkPolicy, gRPC Route, CP token Service,
  RBAC, MCP sidecar, RoleBinding namespace fixes
- production overlay updates
- openshift-dev overlay
- Removed deprecated cluster-reader overlay
- All overlays pass kustomize build

Migration plan updated: PRs 1-5 marked merged, PR 6+7 combined.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
TestGhWrapper._cleanup() used stale top-level imports of _GH_WRAPPER_PATH
(always ""), causing Path(".").unlink() → IsADirectoryError. Now reads from
the module object with empty-string guards. Also fixes e2e workflow Docker
build context from components/runners to components/runners/ambient-runner
so pyproject.toml is found during image build.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
clear_runtime_credentials was deleting the Google Workspace credentials
file between turns, causing workspace-mcp to fall back to an inaccessible
localhost OAuth flow. The file is now intentionally preserved.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Tests were refactored to remove CREDENTIAL_IDS but _fetch_credential
still requires it to look up the credential_id and build the API URL.
Without it, the function returns {} immediately without hitting the
test HTTP server. Also restores credential_id-based response matching
in the lifecycle test.

713 passed, 11 skipped locally.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
…hot tests

The session-list screenshot test failed because setTheme clicked the
toggle button before it was visible in the DOM. Add explicit visibility
wait with 10s timeout to setTheme, matching the pattern already used
in the waitForThemeToggle setup step.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
…requests

The websocket package's agui_proxy.go used plain http.Transport / ad-hoc
http.Client instances that bypassed the runnerTransport session-token layer.
Every runner call from the websocket handlers (connectToRunner, interrupt,
feedback, capabilities, mcp-status, task stop/output/list, between-run
listener) lacked the X-Ambient-Session-Token header, causing HTTP 401s
from runners with AGUI_TOKEN middleware enabled.

- Export NewRunnerTransport from handlers package
- Wrap runnerHTTPClient with handlers.NewRunnerTransport
- Add runnerShortClient (10s) and runnerMediumClient (30s) with token transport
- Replace all 7 ad-hoc http.Client{} calls with the named clients
- Add TDD tests: transport type assertion, end-to-end token injection,
  missing-secret graceful degradation

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
…on parameter mismatch

Two unrelated production issues:

1. vteam_control_plane image was never built by CI — missing from both
   components-build-deploy.yml and prod-release-deploy.yaml. The deployment
   references quay.io/ambient_code/vteam_control_plane:latest which doesn't
   exist, causing ImagePullBackOff. Adds ambient-control-plane to the build
   matrix, path triggers, kustomize image pinning, and the release DEPLOY_MAP.

2. ambient-api-server migration init container crashes with "pq: got 2
   parameters but the statement requires 1". GORM's FirstOrCreate extracts
   non-zero primary key fields as additional WHERE conditions, but the SQL
   placeholder count doesn't match when using .Table(). Fix: use Attrs() to
   defer ID assignment to create-time only, keeping the WHERE clause clean.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 22, 2026

Deploy Preview for cheerful-kitten-f556a0 canceled.

Name Link
🔨 Latest commit d31bfb1
🔍 Latest deploy log https://app.netlify.com/projects/cheerful-kitten-f556a0/deploys/69e8ce73caefa6000824b6c1

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 22, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

Adds a new ambient-mcp component (source, build, Dockerfile, server, client, token exchange, mention resolution, MCP tools, and tests), expands CI/CD workflows to include ambient-control-plane and ambient-mcp, refactors GORM role seeding to use GORM Attrs(), and centralizes runner HTTP transport/clients plus related tests.

Changes

Cohort / File(s) Summary
CI/CD Workflows
.github/workflows/components-build-deploy.yml, .github/workflows/prod-release-deploy.yaml
Added ambient-control-plane and ambient-mcp to path filters, workflow inputs, ALL_COMPONENTS/DEPLOY_MAP, and image/tag pinning logic for OpenShift deployments.
GORM Migration Refactor
components/ambient-api-server/plugins/credentials/migration.go, components/ambient-api-server/plugins/roles/migration.go
Changed role seeding to use an empty roleRow with Attrs(...) on Table(...).Where(...).FirstOrCreate(&row) instead of pre-populating the struct.
Runner HTTP Transport & Clients
components/backend/handlers/sessions.go, components/backend/websocket/agui_proxy.go, components/backend/websocket/agui_proxy_test.go
Added NewRunnerTransport(base http.RoundTripper), replaced inline per-call http.Client usage with shared preconfigured clients (runnerShortClient, runnerMediumClient, runnerHTTPClient) that wrap transports for X-Ambient-Session-Token injection; added tests validating transport and token header behavior.
ambient-mcp: module & container
components/ambient-mcp/go.mod, components/ambient-mcp/Dockerfile
Introduced new Go module for ambient-mcp and a multi-stage UBI9-based Dockerfile producing the ambient-mcp runtime binary.
ambient-mcp: entry & server
components/ambient-mcp/main.go, components/ambient-mcp/server.go
Added executable entrypoint wiring transport/token bootstrap, MCP server startup modes (stdio/sse), and server initialization that registers session/agent/project tools.
ambient-mcp: client lib
components/ambient-mcp/client/client.go, components/ambient-mcp/client/client_test.go
New HTTP client type with token management, request helpers (Get/GetWithQuery/Post/Patch), concurrency-safe token updates, and unit tests covering auth headers, token updates, and request behavior.
ambient-mcp: token exchange
components/ambient-mcp/tokenexchange/tokenexchange.go, components/ambient-mcp/tokenexchange/tokenexchange_test.go
Added Exchanger to fetch and refresh tokens via RSA-OAEP-encrypted session IDs, background refresh, callbacks, validation and retry logic; comprehensive tests including RSA/key handling, retries, and lifecycle.
ambient-mcp: mention resolution
components/ambient-mcp/mention/resolve.go, components/ambient-mcp/mention/resolve_test.go
Added mention extraction/strip utilities and Resolver that resolves identifiers via Ambient API (UUID direct GET or name search), with tests for header/auth usage and resolution/error cases.
ambient-mcp: MCP tools — sessions
components/ambient-mcp/tools/sessions.go, components/ambient-mcp/tools/watch.go
Implemented MCP tool handlers for listing/getting/creating sessions, pushing messages (with mention delegation), patching labels/annotations, and watch/unwatch semantics; includes mention resolution integration and subscriptions registry.
ambient-mcp: MCP tools — agents & projects
components/ambient-mcp/tools/agents.go, components/ambient-mcp/tools/projects.go, components/ambient-mcp/tools/helpers.go
Added agent and project tool handlers (list/get/create/update/patch), helper functions for JSON/error tool results, and annotation/label merge logic; error result mapping and HTTP-backed implementations.
ambient-mcp: tests & large additions
components/ambient-mcp/... (many *_test.go files)
Extensive tests added across client, mention resolver, token exchange, and other components to validate behavior, error cases, concurrency, and integration points.

Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
Security And Secret Handling ❌ Error PR introduces multiple security vulnerabilities: SQL injection via unsanitized identifier escaping, plain HTTP for token exchange with Bearer tokens, missing HTTP timeouts enabling DoS, and discarded error handling. Escape single quotes in search identifiers, restrict HTTP token URLs to loopback only, add 10-second HTTP timeout, handle errors from NewRequestWithContext, and add environment variable for SSE URL scheme.
Docstring Coverage ⚠️ Warning Docstring coverage is 12.94% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (6 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Title follows Conventional Commits format (type: fix, scope: ci,api-server) and clearly describes the two main fixes: CI pipeline updates for control-plane/mcp and GORM migration parameter mismatch resolution.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Performance And Algorithmic Complexity ✅ Passed PR introduces no algorithmic complexity regressions. List operations support optional pagination, mention resolution breaks after first match, regex patterns compiled once, token refresh uses properly-cleaned ticker, and no N+1 patterns observed.
Kubernetes Resource Safety ✅ Passed PR does not introduce or modify Kubernetes resource definitions; changes limited to workflows, Go source code, and Dockerfile.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/ci-control-plane-and-migration
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix/ci-control-plane-and-migration

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

⚠️ SDD Preflight — Managed Paths Modified

This PR modifies files in SDD-managed component(s). These components are migrating to Spec-Driven Development.

File Component Mode
components/runners/ambient-runner/.mcp.json runner warn
components/runners/ambient-runner/architecture.md runner warn
components/runners/ambient-runner/pyproject.toml runner warn

No action required — these components are in warn mode. Consider using the component's agent workflow for future changes.

📖 Specs: Runner Spec · Runner Constitution

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
components/ambient-api-server/plugins/roles/migration.go (1)

109-119: Add a regression test for this migration pattern.

Given this caused a production init crash, add one migration-focused test that asserts FirstOrCreate with this pattern succeeds when the role already exists and when it does not. It will guard both this file and the mirrored credentials migration from ORM behavior regressions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/ambient-api-server/plugins/roles/migration.go` around lines 109 -
119, Add a migration-focused regression test that covers the FirstOrCreate
pattern used in the roles migration: specifically exercise
tx.Table("roles").Where("name = ?", r.name).Attrs(...).FirstOrCreate(&row) (the
roleRow construction that uses api.NewID(),
Name/DisplayName/Description/Permissions/BuiltIn) in two scenarios—one where the
role already exists and one where it does not—asserting the call completes
without error and preserves existing values when present; mirror the same test
pattern for the credentials migration to guard against ORM behavior regressions
(use the same tx.Table/Where/Attrs/FirstOrCreate flow and verify expected row
values and no crashes).
components/backend/websocket/agui_proxy_test.go (1)

125-130: Minor: URL parsing assumes http:// prefix.

rewriteHostTransport slices realURL[len("http://"):] directly. This works because httptest.NewServer returns HTTP URLs, but consider using url.Parse for robustness if this helper gets reused:

u, _ := url.Parse(t.realURL)
rewritten.URL.Host = u.Host

Not blocking—current usage is safe.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/backend/websocket/agui_proxy_test.go` around lines 125 - 130, In
rewriteHostTransport.RoundTrip the code assumes t.realURL starts with "http://"
and slices off a fixed prefix; instead parse t.realURL with url.Parse and assign
rewritten.URL.Host = parsed.Host (and optionally parsed.Scheme to
rewritten.URL.Scheme) so the host is extracted robustly; update the RoundTrip
implementation to use url.Parse on the realURL field before modifying
rewritten.URL.
.github/workflows/prod-release-deploy.yaml (1)

239-240: Centralize component metadata to prevent workflow drift.

The component catalog is duplicated across .github/workflows/prod-release-deploy.yaml and .github/workflows/components-build-deploy.yml. This exact drift caused the prior production miss; consider sourcing both matrices from one canonical file or reusable workflow output.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/prod-release-deploy.yaml around lines 239 - 240, The
duplicated component catalog (entries like "ambient-api-server" and
"ambient-control-plane" in the prod-release-deploy and components-build-deploy
workflows) must be centralized: extract the canonical component list into one
source (a single YAML/JSON file or a reusable workflow that outputs
matrix.components) and update both workflows to load matrix.components from that
source (replace the inline arrays in prod-release-deploy and
components-build-deploy with a step that reads the canonical file or consumes
the reusable workflow output). Ensure the workflows still populate the matrix
key used by the jobs (matrix.components) and remove the duplicated hard-coded
component objects so future changes are made in only the canonical source.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In @.github/workflows/prod-release-deploy.yaml:
- Around line 239-240: The duplicated component catalog (entries like
"ambient-api-server" and "ambient-control-plane" in the prod-release-deploy and
components-build-deploy workflows) must be centralized: extract the canonical
component list into one source (a single YAML/JSON file or a reusable workflow
that outputs matrix.components) and update both workflows to load
matrix.components from that source (replace the inline arrays in
prod-release-deploy and components-build-deploy with a step that reads the
canonical file or consumes the reusable workflow output). Ensure the workflows
still populate the matrix key used by the jobs (matrix.components) and remove
the duplicated hard-coded component objects so future changes are made in only
the canonical source.

In `@components/ambient-api-server/plugins/roles/migration.go`:
- Around line 109-119: Add a migration-focused regression test that covers the
FirstOrCreate pattern used in the roles migration: specifically exercise
tx.Table("roles").Where("name = ?", r.name).Attrs(...).FirstOrCreate(&row) (the
roleRow construction that uses api.NewID(),
Name/DisplayName/Description/Permissions/BuiltIn) in two scenarios—one where the
role already exists and one where it does not—asserting the call completes
without error and preserves existing values when present; mirror the same test
pattern for the credentials migration to guard against ORM behavior regressions
(use the same tx.Table/Where/Attrs/FirstOrCreate flow and verify expected row
values and no crashes).

In `@components/backend/websocket/agui_proxy_test.go`:
- Around line 125-130: In rewriteHostTransport.RoundTrip the code assumes
t.realURL starts with "http://" and slices off a fixed prefix; instead parse
t.realURL with url.Parse and assign rewritten.URL.Host = parsed.Host (and
optionally parsed.Scheme to rewritten.URL.Scheme) so the host is extracted
robustly; update the RoundTrip implementation to use url.Parse on the realURL
field before modifying rewritten.URL.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 58d72c07-2da1-4b12-9973-da1dd62eb69f

📥 Commits

Reviewing files that changed from the base of the PR and between d39cb88 and 9c2b302.

📒 Files selected for processing (7)
  • .github/workflows/components-build-deploy.yml
  • .github/workflows/prod-release-deploy.yaml
  • components/ambient-api-server/plugins/credentials/migration.go
  • components/ambient-api-server/plugins/roles/migration.go
  • components/backend/handlers/sessions.go
  • components/backend/websocket/agui_proxy.go
  • components/backend/websocket/agui_proxy_test.go

req.Header.Set("Content-Type", "application/json")

resp, err := (&http.Client{Timeout: 10 * time.Second}).Do(req)
resp, err := runnerShortClient.Do(req)
req.Header.Set("Content-Type", "application/json")

resp, err := (&http.Client{Timeout: 10 * time.Second}).Do(req)
resp, err := runnerShortClient.Do(req)
return
}
resp, err := (&http.Client{Timeout: 10 * time.Second}).Do(req)
resp, err := runnerShortClient.Do(req)
return
}
resp, err := (&http.Client{Timeout: 10 * time.Second}).Do(req)
resp, err := runnerShortClient.Do(req)
req.Header.Set("Content-Type", "application/json")

resp, err := (&http.Client{Timeout: 10 * time.Second}).Do(req)
resp, err := runnerShortClient.Do(req)
}

resp, err := (&http.Client{Timeout: 30 * time.Second}).Do(req)
resp, err := runnerMediumClient.Do(req)
}

resp, err := (&http.Client{Timeout: 10 * time.Second}).Do(req)
resp, err := runnerShortClient.Do(req)
The ambient-mcp component (Go MCP server providing 16 tools for
sessions, agents, projects, and watch) was never migrated from the
alpha branch. Manifests and control-plane code on main already
reference quay.io/ambient_code/vteam_mcp but no source or CI
pipeline existed to build it.

- Copy components/ambient-mcp/ from upstream/alpha (16 files)
- Add ambient-mcp to components-build-deploy.yml (path triggers,
  build matrix, kustomize image pinning in both deploy jobs)
- Add ambient-mcp to prod-release-deploy.yaml (build matrix,
  comp_image loop for kustomize pinning)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@markturansky markturansky changed the title fix(ci,api-server): add control-plane to build pipelines, fix migration parameter mismatch fix(ci,api-server): add control-plane + mcp to build pipelines, fix migration parameter mismatch Apr 22, 2026
@mergify mergify Bot added the queued label Apr 22, 2026
@mergify
Copy link
Copy Markdown
Contributor

mergify Bot commented Apr 22, 2026

Merge Queue Status

  • Entered queue2026-04-22 13:44 UTC · Rule: default
  • Checks skipped · PR is already up-to-date
  • Merged2026-04-22 13:44 UTC · at d31bfb18ff792c31f3327c0a8f7f1cf4b74f2061 · squash

This pull request spent 12 seconds in the queue, including 2 seconds running CI.

Required conditions to merge

@mergify mergify Bot merged commit 0eaa121 into main Apr 22, 2026
52 of 57 checks passed
@mergify mergify Bot deleted the fix/ci-control-plane-and-migration branch April 22, 2026 13:44
@mergify mergify Bot removed the queued label Apr 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants